/**
 * Copyright 2015 ABSir's Studio
 * 
 * All right reserved
 *
 * Create on 2015年4月13日 上午10:18:05
 */
package com.absir.appserv.system.converter;

import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

import com.absir.appserv.system.adapter.SocketAdapter;
import com.absir.appserv.system.adapter.SocketAdapter.CallbackAdapte;
import com.absir.appserv.system.helper.HelperDatabind;
import com.absir.bean.basis.Base;
import com.absir.bean.core.BeanFactoryUtils;
import com.absir.bean.inject.value.Bean;
import com.absir.core.base.Environment;
import com.absir.core.kernel.KernelClass;
import com.absir.core.util.UtilFuture;
import com.absir.server.on.OnPut;
import com.absir.server.route.body.IBodyConverter;
import com.absir.server.socket.InputSocket.InputSocketAtt;

/**
 * @author absir
 *
 */
@Base
@Bean
public class BodyMsgPack implements IBodyConverter {

	/**
	 * @author absir
	 *
	 * @param <T>
	 */
	@SuppressWarnings("unchecked")
	public static abstract class CallbackMessagePack<T> implements CallbackAdapte {

		/** TYPE_VARIABLE */
		public static final TypeVariable<?> TYPE_VARIABLE = CallbackMessagePack.class.getTypeParameters()[0];

		/** beanType */
		protected Type beanType;

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * com.absir.appserv.system.adapter.SocketAdapter.CallbackAdapte#doWith
		 * (com.absir.appserv.system.adapter.SocketAdapter, byte[])
		 */
		@Override
		public void doWith(SocketAdapter adapter, byte[] buffer) {
			if (buffer == null) {
				doWithBean(null, false, null, adapter);
				return;
			}

			if (buffer.length == 0) {
				doWithBean(null, true, null, adapter);
				return;
			}

			boolean ok = (buffer[0] & InputSocketAtt.ERROR_FLAG) == 0;
			if (beanType == null) {
				beanType = KernelClass.type(getClass(), TYPE_VARIABLE);
				if (beanType == null) {
					beanType = BodyMsgPack.class;
				}
			}

			T bean = null;
			if (ok && beanType != BodyMsgPack.class) {
				int length = buffer.length;
				if (length > 5) {
					try {
						bean = (T) HelperDatabind.read(buffer, 5, length - 5, beanType);

					} catch (Exception e) {
						if (Environment.getEnvironment() == Environment.DEVELOP) {
							e.printStackTrace();
						}
					}
				}
			}

			doWithBean(bean, ok, buffer, adapter);
		}

		/**
		 * @param bean
		 * @param ok
		 * @param buffer
		 * @param adapter
		 */
		public abstract void doWithBean(T bean, boolean ok, byte[] buffer, SocketAdapter adapter);
	}

	/**
	 * @author absir
	 *
	 * @param <T>
	 */
	public static class CallbackMessagePackFuture<T> extends CallbackMessagePack<T> {

		/** future */
		private UtilFuture<T> future = new UtilFuture<T>();

		/**
		 * @return the future
		 */
		public UtilFuture<T> getFuture() {
			return future;
		}

		/**
		 * @return
		 */
		public T getFutureBean() {
			return future.getBean();
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * com.absir.appserv.system.converter.BodyMsgPack.CallbackMessagePack
		 * #doWithBean(java.lang.Object, boolean, byte[],
		 * com.absir.appserv.system.adapter.SocketAdapter)
		 */
		@Override
		public void doWithBean(T bean, boolean ok, byte[] buffer, SocketAdapter adapter) {
			future.setBean(bean);
		}
	}

	/** ME */
	public static final BodyMsgPack ME = BeanFactoryUtils.get(BodyMsgPack.class);

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.absir.core.kernel.KernelList.Orderable#getOrder()
	 */
	@Override
	public int getOrder() {
		return 0;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.absir.server.route.body.IBodyConverter#getContentTypes()
	 */
	@Override
	public String[] getContentTypes() {
		return new String[] { "messagePack" };
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.absir.appserv.system.server.IServerBodyConverter#readBodyParameterValue
	 * (com.absir.server.on.OnPut, int, java.lang.String, java.lang.Class)
	 */
	@Override
	public Object readBodyParameterValue(OnPut onPut, int group, String input, Class<?> parameterType) throws Exception {
		byte[] buffer = input.getBytes();
		return HelperDatabind.read(buffer, 0, buffer.length, parameterType);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.absir.appserv.system.server.IServerBodyConverter#readBodyParameterValue
	 * (com.absir.server.on.OnPut, int, java.io.InputStream, java.lang.Class)
	 */
	@Override
	public Object readBodyParameterValue(OnPut onPut, int group, InputStream inputStream, Class<?> parameterType) throws Exception {
		return HelperDatabind.read(inputStream, parameterType);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.absir.appserv.system.server.IServerBodyConverter#writeAsBytes(com
	 * .absir.server.on.OnPut, java.lang.Object)
	 */
	@Override
	public byte[] writeAsBytes(OnPut onPut, Object returnValue) throws Exception {
		return HelperDatabind.writeAsBytes(returnValue);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.absir.appserv.system.server.IServerBodyConverter#writeValue(com.absir
	 * .server.on.OnPut, java.lang.Object, java.io.OutputStream)
	 */
	@Override
	public void writeValue(OnPut onPut, Object returnValue, OutputStream outputStream) throws Exception {
		HelperDatabind.write(outputStream, returnValue);
	}
}
